
#include <windows.h>
#include <strsafe.h>

#pragma warning( push )
#pragma warning( disable : 4995 )
//#include <stdio.h>
#include <wchar.h>

// 'gets': name was marked as #pragma deprecated
// 'sprintf': name was marked as #pragma deprecated
// 'vsprintf': name was marked as #pragma deprecated
// 'strcat': name was marked as #pragma deprecated
// 'strcpy': name was marked as #pragma deprecated
// 'swprintf': name was marked as #pragma deprecated
// 'vswprintf': name was marked as #pragma deprecated
// 'wcscat': name was marked as #pragma deprecated
// 'wcscpy': name was marked as #pragma deprecated

#include <plog/log.h>
#include <plog/log_message.h>
#include <stdexcept>
//#include <iostream>
#include <string>
#include "Log.h"

#define SERVICE_CONTEXT_INFO    \
    plog::context_info(__FILE__, __FUNCTION__, __LINE__, ::GetCurrentThreadId())
//#define LOG(severity) 
    //*(plog::logger_holder::get_logger()) += plog::message(severity, CONTEXT_INFO)

namespace wrservice
{

Log::Log ()
{
    //::InitializeCriticalSection ( &(this->log_cs_) );
    this->define_log_file_ ();
    plog::initialize_log(this->file_name_, plog::error);
    //plog::initialize_log(L"example.csv", plog::error);
}

Log::~Log ()
{
    plog::release_log();
    //::DeleteCriticalSection ( &(this->log_cs_) );
}

/////////////////////////////////////////////////////////////////////
//
// Goal : 
//   Defines log file name and puts it in szLogFile buffer
//
inline void Log::define_log_file_ ()
{
    DWORD dwSize;
    dwSize = ::GetModuleFileNameW ( NULL, this->file_name_, MAX_PATH );
    if (!dwSize) {
        //::_tprintf ( L"ABORT: Cannot define log file" );
        throw std::runtime_error ("ABORT: Cannot define log file");
    }
    if ( dwSize > 4 && this->file_name_[dwSize-4] == '.' )
    {
        this->file_name_[dwSize-3] = 0;
        ::StringCchCat (this->file_name_, dwSize+1, L"csv");
    }
}

/////////////////////////////////////////////////////////////////////
//
// Goal : 
//   Writes description of an error (dwErrorCode) in buffer lpErrorBuffer
//
inline
void Log::error_description_ (
    __in  DWORD  dwErrorCode,
    __out LPWSTR lpErrorBuffer,
    __in  DWORD  dwBufferSize
    )
{
    HLOCAL hLocal = NULL;
    
    FormatMessageW (
        FORMAT_MESSAGE_FROM_SYSTEM | 
        FORMAT_MESSAGE_ALLOCATE_BUFFER, /* formatting options */
        NULL,                           /* location of the message definition */
        dwErrorCode,                    /* message identifier for the requested message */
        MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
                                        /* language identifier for the requested message */
        (LPWSTR)&hLocal,                /* buffer for formatted message */
        dwBufferSize,                   /* cannot be larger than 64K bytes */
        NULL                            /* array of values in the formatted message */
    );

    StringCchCopy (lpErrorBuffer, dwBufferSize, (LPCWSTR)LocalLock(hLocal));
    LocalFree(hLocal);
}

/////////////////////////////////////////////////////////////////////
//
// Goal : 
//   Handles formatted error and write it into the log file
//
void Log::write_error (LPSTR msg)
{
    wchar_t tmp_buf_ [Log::temp_buffer_size_];
	wchar_t tmp_error_desc_ [Log::temp_buffer_size_/2];
    DWORD   error_code_ = ::GetLastError ();

    this->error_description_ ( 
        error_code_, tmp_error_desc_, Log::temp_buffer_size_/2 );
	swprintf_s ( tmp_buf_, Log::temp_buffer_size_, 
        L"%s, error code = %d\n   %s", msg, error_code_,
		tmp_error_desc_ );
    
    //::EnterCriticalSection ( &(this->log_cs_) );
    LOG(plog::error) << tmp_buf_;
    //::LeaveCriticalSection ( &(this->log_cs_) );
}

/////////////////////////////////////////////////////////////////////
//
// Goal : 
//   Writes occured event into the log file
//
void Log::write_event (LPSTR msg)
{
    //::EnterCriticalSection ( &(this->log_cs_) );
    LOG(plog::info) << msg;
    //::LeaveCriticalSection ( &(this->log_cs_) );
}

} /* namespace wrservice */

#pragma warning( pop )
